package router

import (
	"BaseApi/common/global"
	"BaseApi/proto"
	"context"
	"fmt"
	"github.com/gin-gonic/gin"
	grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/retry"
	"go.uber.org/zap"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/credentials/insecure"
	"time"
)

// 连接rpc端
func InitSrvGrpc() gin.HandlerFunc {
	//使用consule的过滤方法 从consule中直接拿到rpc端的服务信息
	result, err := global.ConsuleClient.Agent().ServicesWithFilter(fmt.Sprintf(`Service == "%s"`, global.GlobalConfig.BaseSrv.Name))
	//将grpc封装成全局调用（之前是单个接口调用）
	userSrvIp := ""
	userPort := 0
	for _, value := range result {
		userSrvIp = value.Address
		userPort = value.Port
		break
	}
	//如果没有取到rpc端服务的host地址 那么直接输出错误
	if userSrvIp == "" {
		zap.S().Info("连接rpc端失败", err)
		panic(err)
	}
	//拦截器：计算耗时时间
	interceptor := func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
		start := time.Now()
		err := invoker(ctx, method, req, reply, cc, opts...)
		zap.S().Info(fmt.Sprintf("耗时：%s\n", time.Since(start)))
		return err
	}
	//定义多个拦截器
	var opts []grpc.DialOption
	opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
	//grpc_retry实现超时重试
	retryOpts := []grpc_retry.CallOption{
		grpc_retry.WithMax(3),                                                          //重试最多3次
		grpc_retry.WithPerRetryTimeout(1 * time.Second),                                //每次最高超时1秒
		grpc_retry.WithCodes(codes.Unknown, codes.DeadlineExceeded, codes.Unavailable), //基于返回codes判断超时机制
	}
	//追加拦截器参数
	opts = append(opts, grpc.WithUnaryInterceptor(interceptor))
	opts = append(opts, grpc.WithUnaryInterceptor(grpc_retry.UnaryClientInterceptor(retryOpts...)))
	//建立连接
	conn, err := grpc.Dial(fmt.Sprintf("%s:%d", userSrvIp, userPort), opts...)
	if err != nil {
		panic(err)
	}
	defer conn.Close()
	//
	//userClient, err := grpc.Dial(
	//	fmt.Sprintf("%s:%d", userSrvIp, userPort),
	//	grpc.WithTransportCredentials(insecure.NewCredentials()),
	//	//grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy"："round_robin"}`), //负载的方式
	//)
	userSrvClient := proto.NewUserClient(conn)

	global.UserClient = userSrvClient
	return nil
}
